package entry.custom.predicate;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

import javax.validation.constraints.NotEmpty;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

/**
 * 自定义Predicate断言，测试不使用静态内部类Config的方式
 * @author libra
 */
@Component
public class SelfPredicateNoInnerConfigRoutePredicateFactory extends AbstractRoutePredicateFactory<SelfPredicateNoInnerConfig> {
	// 构造函数需要将自身的静态内部Config类进行传入
	public SelfPredicateNoInnerConfigRoutePredicateFactory() {
		super(SelfPredicateNoInnerConfig.class);
	}
	
	@Override
	public Predicate<ServerWebExchange> apply(SelfPredicateNoInnerConfig config) {
		// 断言判定的方法实现，true->匹配成功；false->匹配失败；
		return new GatewayPredicate() {
			/**
			 * 当前测试用例：
			 * 	请求方式为post 并且 包含有请求头 selfPredicateHeader=纯数字的正则 且 包含有请求参数 selfPredicateParam=纯数字的正则
			 */
			@Override
			public boolean test(ServerWebExchange serverWebExchange) {
				boolean paramCheck = false, headerCheck = false;
				// 通过该方法获取当次这次的Request请求对象
				ServerHttpRequest request = serverWebExchange.getRequest();
				System.out.println( request.getClass() );
				// 因为所有的断言都会进行判断，因此添加该判断只处理自定义断言的请求
				if( request.getPath().value().indexOf("/gw/predicate/selfCustom2") == -1 )
					return false;
				// 判断请求方式
				if( !config.getMethod().equalsIgnoreCase( request.getMethodValue() ) )
					return false;
				// 判断请求参数
				List<String> paramVals = request.getQueryParams().getOrDefault(config.getParamK(), Collections.emptyList());
				if (paramVals.isEmpty()) 
					return false;
				for ( String param : paramVals ) {
					if (param.matches(config.getParamV())) 
						paramCheck = true;
				}
				// 判断请求头
				List<String> headerVals = request.getHeaders().getOrDefault(config.getHeaderK(), Collections.emptyList());
				if (headerVals.isEmpty()) 
					return false;
				for ( String val : headerVals ) {
					if (val.matches(config.getHeaderV())) 
						headerCheck = true;
				}
				return paramCheck&&headerCheck;
			}
		};
	}
	
	/**
	 * 通过该方法向Config类进行“值”设置
	 * 传入的值即为Config中的属性名，通过查找Config中的set方法进行设置“值”
	 * TIPS:
	 * 	如果yml配置中采用的是predicates.name、predicates.args.属性a/b/c...，的方式配置，shortcutFieldOrder()方法可以不要。
	 */
//	@Override
//	public List<String> shortcutFieldOrder() {
//		return Arrays.asList("headerK","headerV","paramK","paramV","method");
//	}
}
